using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics.Contracts;


namespace FoundationLib.Mail
{
	/// <summary>
	/// A composite mail data item, which can contain multiple atomic mail data items.
	/// </summary>
	public class CompositeMailDataItem : MailDataItem, IEnumerable<List<AtomicMailDataItem>>
	{
		/// <summary>
		/// The rows contained in this composite data item
		/// </summary>
		private List<List<AtomicMailDataItem>> rows;
		/// <summary>
		/// The number of columns for each row
		/// </summary>
		private int columnCount = -1;


		/// <summary>
		/// Creates a new composite mail data item.
		/// </summary>
		/// <param name="key">The data item key</param>
		/// <exception cref="ArgumentNullException">A null-reference was passed.</exception>
		public CompositeMailDataItem(string key) : base(key)
		{
			this.rows = new List<List<AtomicMailDataItem>>();
		}

		/// <summary>
		/// Gets the number of rows in this composite item.
		/// </summary>
		public int RowCount
		{
			get
			{
				return (this.rows.Count);
			}
		}

		/// <summary>
		/// Adds a row to the composite data item.
		/// </summary>
		/// <param name="cells">The cells of this row</param>
		/// <exception cref="ArgumentNullException">A null-reference was passed.</exception>
		/// <exception cref="ArgumentException">The number of cells is not equal to the number of columns.</exception>
		public void Add(params AtomicMailDataItem[] cells)
		{
			Contract.Requires(cells != null);
			Contract.Requires(cells.Length > 0);

			if (this.rows.Count == 0)
				this.columnCount = cells.Length;

			Contract.Assert(cells.Length == this.columnCount, "The number of cells is not equal to the number of columns.");

			List<AtomicMailDataItem> cellList = cells.ToList();
			this.rows.Add(cellList);
		}

		/// <summary>
		/// Removes the row at the specified index.
		/// </summary>
		/// <exception cref="IndexOutOfRangeException">The specified row index is out of
		/// range.</exception>
		/// <param name="row">The row to remove</param>
		public void RemoveAt(int row)
		{
			Contract.Requires(row >= 0);
			Contract.Assert(row < this.rows.Count);
			this.rows.RemoveAt(row);
		}

		/// <summary>
		/// Gets or sets the data item at the given position.
		/// </summary>
		/// <returns>The string data item</returns>
		/// <exception cref="IndexOutOfRangeException">The given index is out of range.
		/// </exception>
		/// <exception cref="ArgumentException">The column index exceeds the number of columns in the composite.</exception>
		/// <param name="row">The row index</param>
		/// <param name="column">The column index</param>
		public AtomicMailDataItem this[int row, int column]
		{
			get
			{
				Contract.Requires(column >= 0 && row >= 0);
				Contract.Assert(column < this.columnCount && row < this.rows.Count);
				return this.rows[row][column];
			}
			set
			{
				Contract.Requires(column >= 0 && row >= 0);
				Contract.Assert(row < this.rows.Count && column < this.columnCount);
				this.rows[row][column] = value;
			}
		}

		/// <summary>
		/// Gets a row from this composite data item.
		/// </summary>
		/// <returns>The data row</returns>
		/// <exception cref="IndexOutOfRangeException">The given index is out of range.
		/// </exception>
		/// <param name="row">The row index</param>
		public AtomicMailDataItem[] this[int row]
		{
			get
			{
				Contract.Requires(row >= 0);
				Contract.Assert(row < this.rows.Count);
				return (this.rows[row].ToArray());
			}
		}

		/// <see cref="IEnumerable{T}.GetEnumerator()"/>
		public IEnumerator<List<AtomicMailDataItem>> GetEnumerator()
		{
			return (this.rows.GetEnumerator());
		}


		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return ((IEnumerable)this.rows).GetEnumerator();
		}
	}

}